package com.mdc.mansion.api.web.common.aop;

import java.util.Date;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.mdc.mansion.api.web.common.context.WebAppContext;
import com.mdc.mansion.common.util.log.LoggerUtil;
/**
 * 日志记录的切面
 * 访问系统方法记录的日志
 * 
 * 目前的spring配置会在 springMVC子容器和spring父容器中都产生一个相同的aop代理对象，可能会有隐患
 * 
 * @author chenmingdong
 * 记录系统中方法请求的日志
 * 2016年1月29日
 */
@Aspect
@Component
public class SystemLogAop{

	//web中的Controller所有的public方法切点
	@Pointcut("execution(public * com.mdc.mansion.api.web..*Controller.*(..))")
	public void logController(){}

	/**
	 * 对Controller层日志记录
	 * 负责一次完整请求的序列号生成与清理
	 * @param point
	 * @return
	 * @throws Throwable
	 */
	@Around("logController()")
	public Object performController(ProceedingJoinPoint point) throws Throwable{
		Date access=new Date();
		long methodInTime=access.getTime();
		String methodName=point.getSignature().getName(); //方法的名称
		String requestSeq = WebAppContext.getRequestSeq(); //生成一次新的
		
		final Logger logger=LoggerFactory.getLogger(point.getSignature().getDeclaringTypeName());
		LoggerUtil.loggerDebug(logger, access, "methodName:"+methodName,requestSeq);
		
		Object ret=invoke(point, methodInTime, methodName, requestSeq,logger);
		afterInvoke(point,methodInTime,methodName,requestSeq,ret,logger,true);
		return ret;
	}
	/**
	 * 被代理对象方法成功执行
	 * @param methodInTime 进入当前对象执行方法的时间
	 * @param methodName 当前被代理执行方法全限定名称
	 * @param requestSeq 当前一次完整请求的序列号
	 * @param ret 执行成功返回的数据
	 * @param logger 
	 */
	private void afterInvoke(ProceedingJoinPoint point,long methodInTime, String methodName,String requestSeq,Object ret,Logger logger,boolean isController) {
		Date access=new Date();
		long methodOutTime = access.getTime(); //方法返回的时间
		long methodExecuteTime=methodOutTime-methodInTime; //方法执行的总时间长度
		if(isController){
			LoggerUtil.loggerInfo(logger, access, methodExecuteTime, "methodName:"+methodName, requestSeq, ret);
		}else{
			LoggerUtil.loggerInfo(logger, access, methodExecuteTime, "methodName:"+methodName, requestSeq, ret, point.getArgs());
		}
	}
	/**
	 * 执行被代理对象方法
	 * @param point 被拦截对象相关信息
	 * @param methodInTime 进入当前对象执行方法的时间
	 * @param methodName 当前被代理执行方法全限定名称
	 * @param requestSeq 当前一次完整请求的序列号
	 * @return
	 * @throws Throwable
	 */
	private Object invoke(ProceedingJoinPoint point, long methodInTime,String methodName, String requestSeq,Logger logger) throws Throwable {
		Object ret=null;
		try {
			ret=point.proceed();
		} catch (Throwable e) {
			Date access=new Date();
			long methodOutTime = access.getTime(); //方法返回的时间
			LoggerUtil.loggerError(logger, access, methodOutTime-methodInTime, "methodName:"+methodName, requestSeq, e, null, point.getArgs());
			throw e;  //记录错误日志后，把错误抛出
		}
		return ret;
	}
}
